1 : <?php
2 : /*--------------------------------------------------------------------------+
3 : This file is part of eStudy.
4 : common/classes/class.spellchecker.inc.php
5 : - Modulgruppe: Framework
6 : - Beschreibung: Implementierung einer Rechtschreibprüfung mittels Aspell.
7 : - Version: 0.3, 05/09/06
8 : - Autor(en): Clemens Weiß <clemens.weiss@mni.fh-giessen.de>
9 : +---------------------------------------------------------------------------+
10 : This program is free software; you can redistribute it and/or
11 : modify it under the terms of the GNU General Public License
12 : as published by the Free Software Foundation; either version 2
13 : of the License, or any later version.
14 : +---------------------------------------------------------------------------+
15 : This program is distributed in the hope that it will be useful,
16 : but WITHOUT ANY WARRANTY; without even the implied warranty of
17 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 : GNU General Public License for more details.
19 : You should have received a copy of the GNU General Public License
20 : along with this program; if not, write to the Free Software
21 : Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 : +--------------------------------------------------------------------------*/
23 : /**
24 : * Implementierung einer Rechtschreibprüfung mittels Aspell.
25 : * Die Klasse sollte nie einzeln auf einen Text angewendet werden,
26 : * sondern immer über den BBCode-Parser.
27 : * @package eStudy.Framework
28 : * @version 0.3, 05/09/06
29 : * @author Clemens Weiß <clemens.weiss@mni.fh-giessen.de>
30 : */
31 : class SpellChecker {
32 : /**
33 : * True, wenn die Rechtschreibprüfung funktioniert, sonst false.
34 : * @var bool
35 : * @access public
36 : */
37 : var $works;
38 : /**
39 : * Pspell-Identifizierung.
40 : * @var int
41 : * @access private
42 : */
43 : var $pspell;
44 : /**
45 : * Konstruktor.
46 : * Erzeugt das Pspell-Objekt und setzt das Attribut $works=false,
47 : * falls Pspell nicht installiert ist.
48 : * Für die Parameter siehe PHP-Manual zu pspell_new().
49 : *
50 : * @access public
51 : * @param string $language Sprache
52 : * @param string $spelling Schreibweise
53 : * @param string $jargon Jargon
54 : */
55 : function SpellChecker($language, $spelling = "", $jargon = "") {
56 0 : $this->works = function_exists("pspell_new");
57 0 : if ($this->works) {
58 0 : $this->pspell = pspell_new($language, $spelling, $jargon);
59 0 : if (!$this->pspell) {
60 0 : $this->works = false;
61 0 : } else {
62 0 : $pwlFile = PATH_TO_ROOT."common/spellchecker.ini";
63 0 : if (file_exists($pwlFile)) {
64 0 : foreach(file($pwlFile) as $word) {
65 0 : $word = trim($word);
66 0 : if (!empty($word) && $word{0} != "#" && preg_match("/^[a-zäöüßÄÖÜ\.']+$/i", $word) && !pspell_check($this->pspell, $word)) {
67 0 : pspell_add_to_session($this->pspell, $word);
68 0 : }
69 0 : }
70 0 : }
71 : }
72 0 : }
73 0 : }
74 : /**
75 : * Durchsucht einen Text nach möglicherweise falsch geschriebenen Wörtern
76 : * und ersetzt solche Wörter durch <span class='misspelled' title='...'>Wort</span>.
77 : * Links, also Wörter innerhalb von a-Tags werden von der Prüfung ausgenommen.
78 : * Sonst wird auf HTML-Tags keine Rücksicht genommen, der Speller sollte also stets
79 : * über den BBCode-Parser aufgerufen werden, damit der Text keine Code-Teile enthält.
80 : * In diesem Zusammenhang wird angenommen, dass alle Sonderzeichen in dem Text
81 : * bereits durch ihre HTML-Entsprechungen ersetzt wurden.
82 : *
83 : * @access public
84 : * @param string $text Zu prüfender Text
85 : * @return string Text mit markierten falsch geschriebenen Wörtern
86 : */
87 : function check($text) {
88 0 : global $settings;
89 0 : if ($this->works) {
90 0 : $delimiter = "\\.,;:`´#~\\^!=%§&_@\\<\\>»«\\+\\$\\*\\?\\-\\|\s\"\\[\\]\\{\\}\\(\\)\\/\\\\".chr(160);
91 : // Strings, die vor der Prüfung entfernt werden sollen (reguläre Ausdrücke)
92 0 : $replaceStrings = array("/\<a.*\<\/a\>/sU", // Links, die durch BBCode::convertBareLinks() entstanden sind
93 0 : );
94 0 : $matches = array();
95 0 : foreach($replaceStrings as $string) {
96 0 : $match = array();
97 0 : $offset = -1;
98 0 : if (preg_match($string, $text, $match, PREG_OFFSET_CAPTURE)) $offset = $match[0][1];
99 0 : while ($offset > -1) {
100 0 : $matches["id"][] = md5($match[0][0]); // zu entfernende Teile zwischenspeichern,
101 0 : $matches["text"][] = $match[0][0]; // damit sie später wieder eingefügt werden können
102 0 : if (preg_match($string, $text, $match, PREG_OFFSET_CAPTURE, $offset+1)) $offset = $match[0][1];
103 0 : else $offset = -1;
104 0 : }
105 0 : }
106 : // zu entfernende Teile durch eindeutige Strings ersetzen
107 0 : if (!empty($matches["text"])) {
108 0 : $text = str_replace($matches["text"], $matches["id"], $text);
109 0 : $delimiter = "[$delimiter]+|".implode("|", $matches["id"]);
110 0 : } else {
111 0 : $delimiter = "[$delimiter]+";
112 : }
113 0 : $words = preg_split("/($delimiter)/", html_entity_decode(strip_tags($text), ENT_COMPAT, $settings["charset"]), -1, PREG_SPLIT_NO_EMPTY);
114 0 : $misspelled = array();
115 0 : if (!empty($words)) {
116 0 : foreach($words as $word) {
117 0 : if (strlen($word) > 1 && !is_numeric($word) && !pspell_check($this->pspell, $word)) {
118 0 : if (substr_count($word, "'")) {
119 : // Ein als falsch erkanntes Wort, das Hochkommata enthält, wird aufgeteilt und
120 : // jeder Teil wird einzeln geprüft. Ist einer der Teile falsch, wird das
121 : // gesamte Wort als falsch markiert.
122 0 : $parts = explode("'", $word);
123 0 : foreach($parts as $part) {
124 0 : if (strlen($part) > 1 && !pspell_check($this->pspell, $part) && !is_numeric($part)) {
125 0 : $misspelled[] = preg_quote(Data::toHTML($word, false), "/");
126 0 : break;
127 : }
128 0 : }
129 0 : } else {
130 0 : $misspelled[] = preg_quote(Data::toHTML($word, false), "/");
131 : }
132 0 : }
133 0 : }
134 0 : }
135 0 : if (!empty($misspelled)) {
136 : // Lookbehind assertion pattern muss feste Länge haben, daher +-Modifikator entfernen
137 0 : $delimiter = str_replace("]+", "]", $delimiter);
138 0 : $pregsearch = "/(?<=^|$delimiter)((<[^>]*)|".implode("|", array_unique($misspelled)) .")(?=$delimiter|$)/eU";
139 0 : $text = preg_replace($pregsearch, '"$2"=="$1" ? "$2" : "<span title=\"Vorschläge: ".Data::toHTML(implode(", ", array_slice(pspell_suggest($this->pspell, "$1"), 0, 5)))."\" class=\"misspelled\">$1</span>"', $text);
140 : // vor Hochkommata befindet sich ein Backslash, der hier entfernt wird (stripslashes() ist hier ungeeignet)
141 : // gibt es noch mehr solche Zeichen, können die beiden Variablen als Arrays festgelegt werden
142 0 : $search = "\'";
143 0 : $replace = "'";
144 0 : $text = str_replace($search, $replace, $text);
145 0 : }
146 : // entfernte Teile in umgekehrter Reihenfolge wieder einfügen
147 0 : if (!empty($matches)) {
148 0 : $text = str_replace(array_reverse($matches["id"]), array_reverse($matches["text"]), $text);
149 0 : }
150 0 : }
151 0 : return $text;
152 : }
153 : }
|